﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

using SharpDX;
using SharpDX.Direct3D10;
using SharpDX.DXGI;
using D2D = SharpDX.Direct2D1;
using D3D9 = SharpDX.Direct3D9;
using Write = SharpDX.DirectWrite;

using Device = SharpDX.Direct3D10.Device;
using Resource = SharpDX.Direct3D10.Resource;

namespace SFSpaceFight
{
	class XLoader
	{
		public XLoader()
		{
			LoadGeometryFromOBJ("/Models/BasicFighter1.obj");
		}

		public Mesh LoadGeometryFromOBJ(string filename)
		{
			string materialfilename = "";
			string wstr = "";

			// temporary storage for the input data
			List<Vector3> positions = new List<Vector3>();
			List<Vector3> texcoords = new List<Vector3>();
			List<Vector3> normals = new List<Vector3>();

			// final input lists that become mesh data
			List<Vertex> vertices = new List<Vertex>();
			List<int> indices = new List<int>();
			List<int> attributes = new List<int>();

			// list to prevent duplicates
			List<int> usedpositions = new List<int>();
			List<string> materialnames = new List<string>();

			// materials
			List <D3D9.ExtendedMaterial> materials = new List<D3D9.ExtendedMaterial>();

			// The first subset uses the default material
			D3D9.ExtendedMaterial material = new D3D9.ExtendedMaterial();
			material.MaterialD3D = new D3D9.Material();
			material.MaterialD3D.Ambient = new Color4(0.2f, 0.2f, 0.2f, 1.0f);
			material.MaterialD3D.Diffuse = new Color4(0.8f, 0.8f, 0.8f, 1.0f);
			material.MaterialD3D.Specular = new Color4(1.0f, 1.0f, 1.0f, 1.0f);
			material.TextureFileName = "default";
			materials.Add( material);

			int dwCurSubset = 0;

			// File input
			StreamReader reader = File.OpenText(filename);

			while (!reader.EndOfStream)
			{
				string[] entries = reader.ReadLine().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

				switch (entries[0])
				{
					case "v": // vertex position
						float[] pos = Array.ConvertAll<string, float>(entries.Skip(1).ToArray(),
							delegate(string s) { float f; float.TryParse(s, out f); return f; });
						positions.Add(new Vector3(pos[0], pos[1], pos[2]));
						break;
					case "vt": // vertex texture coordinates
						float[] tex = Array.ConvertAll<string, float>(entries.Skip(1).ToArray(),
							delegate(string s) { float f; float.TryParse(s, out f); return f; });
						texcoords.Add(new Vector3(tex[0], tex[1], tex[2]));
						break;
					case "vn": // vertex normals
						float[] norm = Array.ConvertAll<string, float>(entries.Skip(1).ToArray(),
							delegate(string s) { float f; float.TryParse(s, out f); return f; });
						normals.Add(new Vector3(norm[0], norm[1], norm[2]));
						break;
					case "f": // faces
						string[] nubs = entries.Skip(1).ToArray();
						int iPosition, iTexCoord, iNormal;
						Vertex vertex;

						for(int iFace = 0; iFace < 3; iFace++ )
						{
							int[] nums = Array.ConvertAll<string, int>(nubs, delegate(string s) { int f; int.TryParse(s, out f); return f; });
							vertex = new Vertex();

							// OBJ format uses 1-based arrays
							iPosition = nums[0];
							vertex.position = positions[ iPosition - 1 ];

							if(nums.Length > 1)
							{
								// Optional texture coordinate
								iTexCoord = nums[1];
								vertex.texcoord = texcoords[ iTexCoord - 1 ];

								if (nums.Length > 2)
								{
									// Optional vertex normal
									iNormal = nums[2];
									vertex.normal = normals[ iNormal - 1 ];
								}
							}

							// If a duplicate vertex doesn't exist, add this vertex to the Vertices
							// list. Store the index in the Indices array. The Vertices and Indices
							// lists will eventually become the Vertex Buffer and Index Buffer for
							// the mesh.

							int index = vertices.Count;

							if (!usedpositions.Contains(iPosition))
							{ // only add unique vertices
								usedpositions.Add(iPosition);
								vertices.Add(vertex);
							}
							else
							{
								index = usedpositions.IndexOf(iPosition);
							}
							indices.Add( index );
						}
						attributes.Add( dwCurSubset );
						break;
					case "mtllib" : // material library
						materialfilename = entries[1];
						break;
					case "usemtl" : // use material
						string strName = "";
						strName = entries[1];

						bool bFound = false;
						for( int iMaterial = 0; iMaterial < materials.Count; iMaterial++ )
						{
							D3D9.ExtendedMaterial pCurMaterial = materials[iMaterial];
							if( string.Equals(pCurMaterial.TextureFileName, strName) )
							{
								bFound = true;
								dwCurSubset = iMaterial;
								break;
							}
						}

						if( !bFound )
						{
							dwCurSubset = materials.Count;

							// initialize material
							material = new D3D9.ExtendedMaterial();
							material.MaterialD3D = new D3D9.Material();
							material.MaterialD3D.Ambient = new Color4(0.2f, 0.2f, 0.2f, 1.0f);
							material.MaterialD3D.Diffuse = new Color4(0.8f, 0.8f, 0.8f, 1.0f);
							material.MaterialD3D.Specular = new Color4(1.0f, 1.0f, 1.0f, 1.0f);
							material.TextureFileName = strName;

							materials.Add( material );
						}
						break;
				}
			}

			// cleanup
			reader.Close();

			// If an associated material file was found, read that in as well.
			if (! string.IsNullOrEmpty(materialfilename))
			{
				//LoadMaterialsFromMTL(materialfilename);
			}

			Mesh returnmesh = new Mesh()
		}


		//private void LoadMaterialsFromMTL( string strFileName )
		//{
		//	// Set the current directory based on where the mesh was found
		//	string wstrOldDir = "";
		//	Directory.GetCurrentDirectory( MAX_PATH, wstrOldDir );
		//	Directory.SetCurrentDirectory( m_strMediaDir );

		//	// Find the file
		//	WCHAR strPath[MAX_PATH];
		//	char cstrPath[MAX_PATH];
		//	V_RETURN( DXUTFindDXSDKMediaFileCch( strPath, MAX_PATH, strFileName ) );
		//	WideCharToMultiByte( CP_ACP, 0, strPath, -1, cstrPath, MAX_PATH, NULL, NULL );

		//	// File input
		//	WCHAR strCommand[256] = {0};
		//	wifstream InFile( cstrPath );
		//	if( !InFile )
		//		return DXTRACE_ERR( L"wifstream::open", E_FAIL );

		//	// Restore the original current directory
		//	SetCurrentDirectory( wstrOldDir );

		//	Material* pMaterial = NULL;

		//	for(; ; )
		//	{
		//		InFile >> strCommand;
		//		if( !InFile )
		//			break;

		//		if( 0 == wcscmp( strCommand, L"newmtl" ) )
		//		{
		//			// Switching active materials
		//			WCHAR strName[MAX_PATH] = {0};
		//			InFile >> strName;

		//			pMaterial = NULL;
		//			for( int i = 0; i < m_Materials.GetSize(); i++ )
		//			{
		//				Material* pCurMaterial = m_Materials.GetAt( i );
		//				if( 0 == wcscmp( pCurMaterial->strName, strName ) )
		//				{
		//					pMaterial = pCurMaterial;
		//					break;
		//				}
		//			}
		//		}

		//		// The rest of the commands rely on an active material
		//		if( pMaterial == NULL )
		//			continue;

		//		if( 0 == wcscmp( strCommand, L"#" ) )
		//		{
		//			// Comment
		//		}
		//		else if( 0 == wcscmp( strCommand, L"Ka" ) )
		//		{
		//			// Ambient color
		//			float r, g, b;
		//			InFile >> r >> g >> b;
		//			pMaterial->vAmbient = D3DXVECTOR3( r, g, b );
		//		}
		//		else if( 0 == wcscmp( strCommand, L"Kd" ) )
		//		{
		//			// Diffuse color
		//			float r, g, b;
		//			InFile >> r >> g >> b;
		//			pMaterial->vDiffuse = D3DXVECTOR3( r, g, b );
		//		}
		//		else if( 0 == wcscmp( strCommand, L"Ks" ) )
		//		{
		//			// Specular color
		//			float r, g, b;
		//			InFile >> r >> g >> b;
		//			pMaterial->vSpecular = D3DXVECTOR3( r, g, b );
		//		}
		//		else if( 0 == wcscmp( strCommand, L"d" ) ||
		//				 0 == wcscmp( strCommand, L"Tr" ) )
		//		{
		//			// Alpha
		//			InFile >> pMaterial->fAlpha;
		//		}
		//		else if( 0 == wcscmp( strCommand, L"Ns" ) )
		//		{
		//			// Shininess
		//			int nShininess;
		//			InFile >> nShininess;
		//			pMaterial->nShininess = nShininess;
		//		}
		//		else if( 0 == wcscmp( strCommand, L"illum" ) )
		//		{
		//			// Specular on/off
		//			int illumination;
		//			InFile >> illumination;
		//			pMaterial->bSpecular = ( illumination == 2 );
		//		}
		//		else if( 0 == wcscmp( strCommand, L"map_Kd" ) )
		//		{
		//			// Texture
		//			InFile >> pMaterial->strTexture;
		//		}

		//		else
		//		{
		//			// Unimplemented or unrecognized command
		//		}

		//		InFile.ignore( 1000, L'\n' );
		//	}

		//	InFile.close();

		//	return S_OK;
		//}


		struct Vertex
		{
			public Vector3 position;
			public Vector3 normal;
			public Vector3 texcoord;
		};
	}
}
